package tx.core.input;


/**
 * The GameAction class is an abstract to a user-initiated action,
 * like jumping or moving. GameActions can be mapped to keys
 * or the mouse with the InputManager.
 * 
 * This class is based on GameAction class, by David Brackeen.
 * @author Guilherme Mauro Germoglio Barbosa - germoglio@gmail.com
 *
 */
public class GameAction {
	
	/**
	 * Normal behavior. The <code>isPressed()</code> method returns
	 * <code>true</code> as long as the key is held down.
	 */
	public static final int NORMAL = 0;
	
	/**
	 * Initial press behavior. The <code>isPressed()</code> method returns
	 * <code>true</code> only after the key is first pressed, and not again until
	 * the key is released and pressed again. 
	 */
	public static final int DETECT_INITIAL_PRESS_ONLY = 1;
	
	/**
	 * Constants for state of the key: released.
	 */
	private static final int STATE_RELEASED = 0;
	/**
	 * Constants for state of the key: pressed.
	 */
	private static final int STATE_PRESSED = 1;
	/**
	 *  Constants for state of the key: waiting for release.
	 */
	private static final int STATE_WAITING_FOR_RELEASE = 2;
	
	/**
	 * The name.
	 */
	private String name;
	
	/**
	 * The behavior.
	 */
	private int behavior;
	
	/**
	 * The amount.
	 */
	private int amount;
	
	/**
	 * The current state,
	 */
	private int state;
	
	/**
	 * Creates new GameAction with the <code>NORMAL</code> behavior.
	 * @param name The GameAction's name.
	 */
	public GameAction(String name) {
		this(name, NORMAL);
	}
	
	/**
	 * Creates a new GameAction with the specified behavior.
	 * @param name The GameAction's name.
	 * @param behavior The action's behavior.
	 */
	public GameAction(String name, int behavior) {
		this.name = name;
		this.behavior = behavior;
		this.reset();
	}
	
	/**
	 * Returns the name.
	 * @return The name.
	 */
	public String getName() {
		return name;
	}
	
	/**
	 * Resets the GameAction so that it appears like it hasn't been pressed.
	 */
	public void reset() {
		state = STATE_RELEASED;
		amount = 0;
	}
	
	/**
	 * Taps this GameAction. Same as calling <code>press()</code> followed
	 * by <code>release()</code>.
	 */
	public synchronized void tap() {
		press();
		release();
	}
	
	/**
	 * Signals that the key was pressed.
	 */
	public synchronized void press() {
		press(1);
	}
	
	/**
	 * Signals that the key was pressed a specified number of times, or
	 * that the mouse moved a specified distance.
	 * @param amount The amount of times pressed / the distance the mouse moved.
	 */
	public synchronized void press(int amount) {
		if (state != STATE_WAITING_FOR_RELEASE) {
			this.amount += amount;
			state = STATE_PRESSED;
		}
	}
	
	/**
	 * Signals the key was released. 
	 */
	public synchronized void release() {
		state = STATE_RELEASED;
	}
	
	/**
	 * Returns whether the key was pressed or not since last checked.
	 * @return <code>true</code> if the key was pressed, <code>false</code> 
	 * otherwise.
	 */
	public synchronized boolean isPressed() {
		return (getAmount() != 0);
	}
	
	/**
	 * For keys, this is the number of times the key was pressed since
	 * it was last checked. For mouse movement, this is the distance moved.
	 * @return For keys, the number of times the key was pressed since
	 * it was last checked. For mouse movement, the distance moved.
	 */
	public synchronized int getAmount() {
		int retVal = amount;
		if (retVal != 0) {
			if (state == STATE_RELEASED) {
				amount = 0;
			} else {
				if (behavior == DETECT_INITIAL_PRESS_ONLY) {
					state = STATE_WAITING_FOR_RELEASE;
					amount = 0;
				}
			}
		}
		return retVal;
	}
}
